package com.astrob.naviframe;

import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import android.annotation.SuppressLint;
import android.graphics.Point;

import com.astrob.NavFrameSDK;
import com.astrob.NavFrameSDK.AreaDescription;
import com.astrob.NavFrameSDK.CLonLat;
import com.astrob.NavFrameSDK.CPoint;
import com.astrob.NavFrameSDK.CllDegreePreMeter;
import com.astrob.NavFrameSDK.GuideInfo;
import com.astrob.NavFrameSDK.NavDest;
import com.astrob.NavFrameSDK.NavInfo;
import com.astrob.NavFrameSDK.NavPosition;
import com.astrob.NavFrameSDK.NavSetting;
import com.astrob.NavFrameSDK.NavStart;
import com.astrob.NavFrameSDK.POIDescription;
import com.astrob.NavFrameSDK.PathLengthInfo;
import com.astrob.NavFrameSDK.RoadDescription;
import com.astrob.NavFrameSDK.RouteErrorInfo;
import com.astrob.NavFrameSDK.RouteOption;
import com.astrob.NavFrameSDK.SDCurPosStates;
import com.astrob.NavFrameSDK.SignPostInfo;
import com.astrob.NavFrameSDK.TurnInfo;
import com.astrob.activitys.AppContext;
import com.astrob.model.LonLat;
import com.astrob.model.SearchParm;
import com.astrob.model.SystemSetFileHandle;
import com.astrob.nhcmap.R;
import com.iflytek.tts.TtsService.TtsSpeaker;
import com.nhc.database.dbmodel.WayPoint;

public class MapKit {

    public int mGIS = 0;
    public int mhSQ = 0;

    public String mSelCityName = "上海";
    public CLonLat mCityPosition = NavFrameSDK.getInstance().new CLonLat();
    public String mDefaultCityName = "上海";

    public boolean initialize(String rundir) {
        mGIS = NavFrameSDK.getInstance().Create(rundir);
        if (mGIS == 0)
            return false;

        mCityPosition.lon = 121.476455;
        mCityPosition.lat = 31.231706;

        TtsSpeaker.getInstance().init(rundir + "/Resource.irf");
        NavFrameSDK.getInstance().SetLanguage(mGIS, 0);//0-中文 1-英文
//		setLodcfg("lod_chi.cfg");
        setCarRouteOption();
        mhSQ = NavFrameSDK.getInstance().SQCreate("");

        return true;
    }

    ;

    @Override
    public void finalize() {
        NavFrameSDK.getInstance().SQDestroy(mhSQ);
        mhSQ = 0;
        NavFrameSDK.getInstance().Destroy(mGIS);
        mGIS = 0;
    }

    public void setLodcfg(String lodcfg) {
        if (mGIS == 0)
            return;
        NavFrameSDK.getInstance().SetLodcfg(mGIS, lodcfg);
    }

    public LonLat XY2LL(Point pos) {
        if (mGIS == 0)
            return null;
        CLonLat ll = NavFrameSDK.getInstance().new CLonLat();
        CPoint xy = NavFrameSDK.getInstance().new CPoint();
        xy.x = pos.x;
        xy.y = pos.y;
        NavFrameSDK.getInstance().XY2LL(mGIS, xy, ll);
        LonLat ret = new LonLat();
        ret.SetLonLat(ll.lon, ll.lat);
        return ret;
    }

    public Point LL2XY(LonLat ll, int mapindex) {
        if (mGIS == 0)
            return null;
        CLonLat cll = NavFrameSDK.getInstance().new CLonLat();
        cll.lon = ll.GetLon();
        cll.lat = ll.GetLat();
        CPoint xy = NavFrameSDK.getInstance().new CPoint();
        NavFrameSDK.getInstance().LL2XY(mGIS, cll, xy, mapindex);
        Point pos = new Point();
        pos.x = (int) xy.x;
        pos.y = (int) xy.y;
        return pos;
    }

    public Point LL2XY(LonLat ll) {
        if (mGIS == 0)
            return null;
        CLonLat cll = NavFrameSDK.getInstance().new CLonLat();
        cll.lon = ll.GetLon();
        cll.lat = ll.GetLat();
        CPoint xy = NavFrameSDK.getInstance().new CPoint();
        NavFrameSDK.getInstance().LL2XY(mGIS, cll, xy, 1);
        Point pos = new Point();
        pos.x = (int) xy.x;
        pos.y = (int) xy.y;
        return pos;
    }

    public Point CrLL2XY(LonLat ll) {
        if (mGIS == 0)
            return null;
        CLonLat cll = NavFrameSDK.getInstance().new CLonLat();
        cll.lon = ll.GetLon();
        cll.lat = ll.GetLat();
        CPoint xy = NavFrameSDK.getInstance().new CPoint();
        NavFrameSDK.getInstance().CrLL2XY(mGIS, cll, xy);
        Point pos = new Point();
        pos.x = (int) xy.x;
        pos.y = (int) xy.y;
        return pos;
    }

    public int setMapCenter(LonLat pos) {
        if (mGIS == 0 || pos == null)
            return 0;
        CLonLat cll = NavFrameSDK.getInstance().new CLonLat();
        cll.lon = pos.GetLon();
        cll.lat = pos.GetLat();
        if (cll.lon == 0) {
            cll.lon = SystemSetFileHandle.getInstance().getSystemSet().previewLon;
            cll.lat = SystemSetFileHandle.getInstance().getSystemSet().previewLat;
        }
        NavFrameSDK.getInstance().SetMapCenter(mGIS, cll);
        return 1;
    }

    public int setMapCenter(double dLon, double dLat) {
        if (mGIS == 0)
            return 0;
        CLonLat pos = NavFrameSDK.getInstance().new CLonLat();
        if (dLon == 0) {
            dLon = SystemSetFileHandle.getInstance().getSystemSet().previewLon;
            dLat = SystemSetFileHandle.getInstance().getSystemSet().previewLat;
        }
        pos.lon = dLon;
        pos.lat = dLat;
        NavFrameSDK.getInstance().SetMapCenter(mGIS, pos);
        return 1;
    }

    public LonLat getMapCenter() {
        if (mGIS == 0)
            return null;
        CLonLat cll = NavFrameSDK.getInstance().new CLonLat();
        NavFrameSDK.getInstance().GetMapCenter(mGIS, cll);
        LonLat ll = new LonLat(cll.lon, cll.lat);
        return ll;
    }
//160,228 （320，457）
    public boolean setPosition(Point DevPt, LonLat mapPt) {
        if (mGIS == 0)
            return false;
        CLonLat pos = NavFrameSDK.getInstance().new CLonLat();
        pos.lon = mapPt.GetLon();
        pos.lat = mapPt.GetLat();

        CPoint xy = NavFrameSDK.getInstance().new CPoint();
        xy.x = DevPt.x;
        xy.y = DevPt.y;

        return NavFrameSDK.getInstance().SetMapPosition(mGIS, xy, pos);
    }

    public boolean setSecondMapPosition(Point DevPt, LonLat mapPt) {
        CLonLat pos = NavFrameSDK.getInstance().new CLonLat();
        pos.lon = mapPt.GetLon();
        pos.lat = mapPt.GetLat();

        CPoint xy = NavFrameSDK.getInstance().new CPoint();
        xy.x = DevPt.x;
        xy.y = DevPt.y;

        return NavFrameSDK.getInstance().SetSecondMapPosition(mGIS, xy, pos);
    }

    public void setRotation(double degree) {
        if (mGIS == 0)
            return;
        mMapRotation = degree;
        NavFrameSDK.getInstance().Rotate(mGIS, degree);
    }

    public void setRotation(double degree, int mapindex) {
        if (mGIS == 0)
            return;
        if (mapindex == 1) {
            mMapRotation = degree;
            NavFrameSDK.getInstance().Rotate(mGIS, degree);
        } else {
            NavFrameSDK.getInstance().RotateSecondMap(mGIS, degree);
        }
    }

    private double mMapRotation = 0;

    public double getRotation() {
        return mMapRotation;
    }

    // mapindex: 1 单屏地图 2双屏右边的图
    public void setMapSize(int Width, int Height, int mapindex) {
        if (mGIS == 0)
            return;

        if (mapindex == 1) {
            NavFrameSDK.getInstance().SetMapSize(mGIS, Width, Height);
        } else {
            NavFrameSDK.getInstance().SetSecondMapSize(mGIS, Width, Height);
        }
    }

    public void setMapSize(int Width, int Height) {
        if (mGIS == 0)
            return;
        NavFrameSDK.getInstance().SetMapSize(mGIS, Width, Height);
    }

    public void setCrMapSize(int Width, int Height) {
        NavFrameSDK.getInstance().SetCrMapSize(mGIS, Width, Height);
    }

    public double getDistance(LonLat mapPt1, LonLat mapPt2) {
        if (mGIS == 0)
            return 0;

        CLonLat pt1 = NavFrameSDK.getInstance().new CLonLat();
        pt1.lon = mapPt1.GetLon();
        pt1.lat = mapPt1.GetLat();

        CLonLat pt2 = NavFrameSDK.getInstance().new CLonLat();
        pt2.lon = mapPt2.GetLon();
        pt2.lat = mapPt2.GetLat();

        return NavFrameSDK.getInstance().GetDistance(mGIS, pt1, pt2);
    }

    public void setScale(double dScale) {
        if (mGIS == 0)
            return;
        NavFrameSDK.getInstance().SetScale(mGIS, dScale);
    }

    public void setScale(double dScale, int mapindex) {
        if (mGIS == 0)
            return;
        if (mapindex == 1) {
            NavFrameSDK.getInstance().SetScale(mGIS, dScale);
        } else {
            NavFrameSDK.getInstance().SetSecondMapScale(mGIS, dScale);
        }
    }

    private final double MAPSCALE[] = {10.0, 50.0, 125.0, 250.0, 500.0,
            1000.0, 2500.0, 5000.0, 10000.0, 25000.0, 50000.0, 100000.0,
            150000.0, 200000.0, 400000.0};

    public boolean onZoomIn() {
        double scale = getScale();
        int indexScale = 0;
        for (int i = 0; i < MAPSCALE.length; i++) {
            if (scale <= MAPSCALE[i]) {
                indexScale = i;
                break;
            }
        }
        if (indexScale >= MAPSCALE.length - 1) {
            return false;
        }
        indexScale++;
        if (indexScale >= MAPSCALE.length - 1) {
            indexScale = MAPSCALE.length - 1;
        }

        setScale(MAPSCALE[indexScale]);
        return true;
    }

    public void onZoomOut() {
        double scale = getScale();
        int indexScale = MAPSCALE.length;
        for (int i = 0; i < MAPSCALE.length; i++) {
            if (scale <= MAPSCALE[i]) {
                indexScale = i;
                break;
            }
        }
        indexScale--;
        if (indexScale < 0) {
            indexScale = 0;
        }

        setScale(MAPSCALE[indexScale]);
    }

    public boolean checkZoomScale(float s) {
        double scale = getScale();
        int indexScale = 0;
        for (int i = 0; i < MAPSCALE.length; i++) {
            if (scale <= MAPSCALE[i]) {
                indexScale = i;
                break;
            }
        }

        int newIndexScale = MAPSCALE.length - 1;
        scale = getScale() * s;

        for (int i = 0; i < MAPSCALE.length; i++) {
            if (scale <= MAPSCALE[i]) {
                newIndexScale = i;
                break;
            }
        }

        if (newIndexScale == indexScale) {
            if (s > 1) {
                newIndexScale = indexScale + 1;
            } else {
                newIndexScale = indexScale - 1;
            }
        }

        if (newIndexScale < 0) {
            newIndexScale = 0;
        }

        if (newIndexScale > MAPSCALE.length - 1) {
            newIndexScale = MAPSCALE.length - 1;
        }

        return (newIndexScale == indexScale);
    }

    public void zoomScale(float s) {
        double scale = getScale();
        double scaleNew = scale * s;
        setScale(scaleNew);
//		int indexScale = 0;
//		for (int i = 0; i < MAPSCALE.length; i++) {
//			if (scale <= MAPSCALE[i]) {
//				indexScale = i;
//				break;
//			}
//		}
//
//		int newIndexScale = MAPSCALE.length - 1;
//		scale = getScale() * s;
//
//		for (int i = 0; i < MAPSCALE.length; i++) {
//			if (scale <= MAPSCALE[i]) {
//				newIndexScale = i;
//				break;
//			}
//		}
//
//		if (newIndexScale == indexScale) {
//			if (s > 1) {
//				newIndexScale = indexScale + 1;
//			} else {
//				newIndexScale = indexScale - 1;
//			}
//		}
//
//		if (newIndexScale < 0) {
//			newIndexScale = 0;
//		}
//
//		if (newIndexScale > MAPSCALE.length - 1) {
//			newIndexScale = MAPSCALE.length - 1;
//		}
//
//		setScale(MAPSCALE[newIndexScale]);
    }

    public boolean rescaleAndTranslateToFit(double MinLon, double MinLat,
                                            double MaxLon, double MaxLat) {
        return NavFrameSDK.getInstance().RescaleAndTranslateToFit(mGIS, MinLon,
                MinLat, MaxLon, MaxLat);
    }

    public double getScale() {
        if (mGIS == 0)
            return -1;
        return NavFrameSDK.getInstance().GetScale(mGIS);
    }

    public double getScale(int mapindex) {
        if (mGIS == 0)
            return -1;
        if (mapindex == 1) {
            return NavFrameSDK.getInstance().GetScale(mGIS);
        } else {
            return NavFrameSDK.getInstance().GetSecondMapScale(mGIS);
        }
    }

    public int getScaleInMeter() {
        if (mGIS == 0)
            return -1;
        return NavFrameSDK.getInstance().GetScaleInMeter(mGIS);
    }

    public int getScaleInMeter(int mapindex) {
        if (mGIS == 0)
            return -1;
        if (mapindex == 1) {
            return NavFrameSDK.getInstance().GetScaleInMeter(mGIS);
        } else {
            return NavFrameSDK.getInstance().GetSecondMapScaleInMeter(mGIS);
        }
    }

    //返回栅格图比例尺
    public int getScaleLevel() {
        int level = 16;
        if (mGIS == 0)
            return level;

        double scale = getScale();
        if (scale >= 400000) {
            level = 19;//10米比例尺 5米间隔
        } else if (scale >= 200000) {
            level = 18;//25米比例尺
        } else if (scale >= 100000) {
            level = 17;//50米比例尺  -- GeoHash
        } else if (scale >= 50000) {
            level = 16;//100米比例尺
        } else if (scale >= 25000) {
            level = 15;
        } else if (scale >= 12500) {
            level = 14;
        } else if (scale >= 6250) {
            level = 13;
        } else if (scale >= 3125) {
            level = 12;
        } else if (scale >= 1600) {
            level = 11;
        } else if (scale >= 800) {
            level = 10;
        } else if (scale >= 400) {
            level = 9;
        } else if (scale >= 200) {
            level = 8;
        } else if (scale >= 100) {
            level = 7;
        } else if (scale >= 50) {
            level = 6;
        } else if (scale >= 25) {
            level = 5;
        } else if (scale >= 12) {
            level = 4;
        } else if (scale >= 6) {
            level = 3;
        } else if (scale >= 3) {
            level = 2;
        } else {
            level = 1;
        }
        return level;
    }

    //由当前比例尺确定 返回 GeoHash的精度-字符串的有效长度 left
    public int getGeoHashLevel(int level) {
        int len = 8;
        if (level >= 19) {
            len = 10;//10米比例尺 -- 精确到1米
        } else if (level >= 18) {
            len = 10;//25米比例尺
        } else if (level >= 17) {
            len = 9;//50米比例尺
        } else if (level >= 16) {
            len = 9;//100米比例尺  精确19m
        } else if (level >= 15) {
            len = 8;
        } else if (level >= 14) {
            len = 8;
        } else if (level >= 13) {
            len = 7;
        } else if (level >= 12) {
            len = 7;
        } else if (level >= 11) {
            len = 6;
        } else if (level >= 10) {
            len = 6;
        } else if (level >= 9) {
            len = 6;
        } else if (level >= 8) {
            len = 5;
        } else if (level >= 7) {
            len = 5;
        } else if (level >= 6) {
            len = 4; //100km
        } else if (level >= 5) {
            len = 3;
        } else if (level >= 4) {
            len = 3;
        } else if (level >= 3) {
            len = 3;
        } else if (level >= 2) {
            len = 3;
        } else {
            len = 3;
        }
        return len;
    }

    public String getScaleString() {
        return getDistanceString(getScaleInMeter(1));
    }

    public String getScaleString(int mapindex) {
        return getDistanceString(getScaleInMeter(mapindex));
    }

    public String getDistanceString(int distance) {
        String distanceString = "";
        if (distance >= 10000) {
            distanceString = distance / 1000 + " km";
        } else if (distance >= 1000) {
            distance = distance / 100;
            double d = distance;
            distanceString = d / 10.0 + " km";
        } else {
            distanceString = distance + " m";
        }

        return distanceString;
    }

    public int mOldMapViewMode = -1;

    public void setMapViewMode(int iDim) {
        mOldMapViewMode = iDim;
        NavFrameSDK.getInstance().SetMapViewMode(mGIS, iDim);
    }

    public void setDayNight(int iDN) {
        boolean isDay = iDN > 0 ? true : false;
        NavFrameSDK.getInstance().SetDayNight(mGIS, isDay);
        NavFrameSDK.getInstance().SetSecondMapDayNight(mGIS, isDay);
        setMapCenter(SystemSetFileHandle.getInstance().getSystemSet()
                .getPreview());

    }

    public void setMapstyle(int styleIndex) {
        NavFrameSDK.getInstance().SetMapstyle(mGIS, styleIndex);
        NavFrameSDK.getInstance().SetSecondMapstyle(mGIS, styleIndex);
        setDayNight(mMapDNState);
    }

    public void setRouteDrawMode(int mode) {
        if (mGIS == 0)
            return;
        NavFrameSDK.getInstance().SetRouteDrawMode(mGIS, mode);
    }

    // 当前地图的日夜间状
    public int mMapDNState = 1; // 1--day 0--night

    public void setDNMode(int DNState) {
        mMapDNState = DNState;
        setDayNight(mMapDNState);
    }

    public int getDNMode() {
        return mMapDNState;
    }

    @SuppressLint("SimpleDateFormat")
    public boolean getDNState() {
        boolean isDay = true;
        SimpleDateFormat formatter = new SimpleDateFormat("HH:mm");
        Date curDate = new Date(System.currentTimeMillis());
        String strTime = formatter.format(curDate);
        if (mSunriseTime == "") {
            mSunriseTime = getSunriseTime();
        }
        if (mSunsetTime == "") {
            mSunsetTime = getSunsetTime();
        }
        String sunrise = mSunriseTime;
        String sunset = mSunsetTime;
        if (strTime.compareToIgnoreCase(sunrise) < 0
                || strTime.compareToIgnoreCase(sunset) >= 0) {
            isDay = false;
        }
        return isDay;
    }

    public void checkDNMode() {
        int DNState = 1;
        if (!getDNState()) {
            DNState = 0;
        }

        if (mMapDNState != DNState) {
            mMapDNState = DNState;
            setDayNight(mMapDNState);
        }
    }

    public void drawPOI(boolean isDraw) {
        if (mGIS == 0)
            return;
        NavFrameSDK.getInstance().DrawPoint(mGIS, isDraw);
    }

    //nStyle  0-线  1-面
    public void addPoly(CLonLat llArray[], int nStyle, int color, int nWidth, int type) {
        if (mGIS == 0)
            return;
        NavFrameSDK.getInstance().AddPoly(mGIS, llArray, nStyle, color, nWidth, type);
    }

    public void clearPoly() {
        if (mGIS == 0)
            return;
        NavFrameSDK.getInstance().ClearPoly(mGIS);
    }

    public void drawMap(byte[] bitmap) {
        if (mGIS == 0)
            return;
        NavFrameSDK.getInstance().Draw(mGIS, bitmap);
    }

    public void drawMap(int mapindex, byte[] bitmap) {
        if (mGIS == 0)
            return;
        if (mapindex == 1)
            NavFrameSDK.getInstance().Draw(mGIS, bitmap);
        else
            NavFrameSDK.getInstance().DrawSecondMap(mGIS, bitmap);
    }

    public boolean drawCrMap(byte[] bitmap) {
        if (mGIS == 0)
            return false;
        return NavFrameSDK.getInstance().DrawCr(mGIS, bitmap);
    }

    public void moveMap(int dx, int dy) {
        if (mGIS == 0)
            return;
        NavFrameSDK.getInstance().MoveMap(mGIS, dx, dy);
    }

    public void clearSMFbuffer() {
        finishGetPOI();
    }

    // navisetting
    private NavSetting mNavSetting = null;

    public NavSetting getNavSetting() {
        if (mNavSetting == null) {
            mNavSetting = NavFrameSDK.getInstance().new NavSetting();
            mNavSetting.hw = 120;
            mNavSetting.gd = 80;
            mNavSetting.pm = 80;
            mNavSetting.drawRoute = true;
            mNavSetting.drawRouteTMC = true;
            mNavSetting.alertOverSpeed = true;
            mNavSetting.recal = true;
            mNavSetting.novice = true;
        }
        return mNavSetting;
    }

    public void setNavSetting(NavSetting navSetting) {
        if (mGIS == 0)
            return;
        mNavSetting = navSetting;
        NavFrameSDK.getInstance().SetNavSetting(mGIS, navSetting);
    }

    // route
    public RouteOption mRouteOption = null;

    public boolean setRouteOption(RouteOption routeOption) {
        if (mGIS == 0)
            return false;
        mRouteOption = routeOption;
        return NavFrameSDK.getInstance().SetRouteOption(mGIS, routeOption);
    }

    public boolean isCarRouteOption() {
        return mRouteOption.bFastest;
    }

    public void setCarRouteOptionNoLimit() {
        RouteOption routeOption = NavFrameSDK.getInstance().new RouteOption();
        routeOption.bFastest = true;
        routeOption.bHighway = true;
        routeOption.bToll = false;
        routeOption.bTurnLimit = false;
        routeOption.bFerry = true;
        routeOption.bMetro = false;
        setRouteOption(routeOption);
    }

    public void setCarRouteOption() {
        RouteOption routeOption = NavFrameSDK.getInstance().new RouteOption();
        routeOption.bFastest = true;
        routeOption.bHighway = true;
        routeOption.bToll = false;
        routeOption.bTurnLimit = true;
        routeOption.bFerry = true;
        routeOption.bMetro = false;
        setRouteOption(routeOption);
    }

    public void setWalkRouteOption() {
        RouteOption routeOption = NavFrameSDK.getInstance().new RouteOption();
        routeOption.bFastest = false;
        routeOption.bHighway = false;
        routeOption.bToll = true;
        routeOption.bTurnLimit = false;
        routeOption.bFerry = true;
        routeOption.bMetro = false;
        setRouteOption(routeOption);
    }

    public void getMapViewExtent(LonLat ld, LonLat ru) {
        if (mGIS == 0)
            return;
        CLonLat pt1 = NavFrameSDK.getInstance().new CLonLat();
        CLonLat pt2 = NavFrameSDK.getInstance().new CLonLat();
        NavFrameSDK.getInstance().GetMapViewExtent(mGIS, pt1, pt2);
        ld.SetLonLat(pt1.lon, pt1.lat);
        ru.SetLonLat(pt2.lon, pt2.lat);
    }

    public boolean getCurPathLengthInfo(PathLengthInfo lengthInfo,
                                        boolean frombegin) {
        if (mGIS == 0)
            return false;
        return NavFrameSDK.getInstance().GetCurPathLengthInfo(mGIS, lengthInfo,
                frombegin);
    }

    public boolean getMultiPathLengthInfo(int index, PathLengthInfo lengthInfo) {
        if (mGIS == 0)
            return false;
        return NavFrameSDK.getInstance().GetMultiPathLengthInfo(mGIS, index,
                lengthInfo);
    }

    public boolean selectPath(int index, boolean copytocurpath,
                              boolean clearcurpath) {
        if (mGIS == 0)
            return false;
        return NavFrameSDK.getInstance().SelectMultiPath(mGIS, index,
                copytocurpath, clearcurpath);
    }

    public int route(NavStart pNavStart, NavDest destArray[],
                     RouteErrorInfo pErrInfo) {
        mNavStart = pNavStart;
        mNavDest = destArray;
        pErrInfo = NavFrameSDK.getInstance().new RouteErrorInfo();
        return NavFrameSDK.getInstance().Route(mGIS, pNavStart, destArray,
                pErrInfo);
    }

    public NavStart mNavStart = NavFrameSDK.getInstance().new NavStart();
    public NavDest mNavDest[] = null; //还是火星坐标

    public void clearNavStart() {
        mNavStart.pos.lon = 0;
        mNavStart.name = "";
        mNavStart.eid = 0;
    }

    public void showFullPath(double previewLon, double previewLat) {
        double MinLon = 10000;
        double MinLat = 10000;
        double MaxLon = -1000;
        double MaxLat = -1000;
        CLonLat pts[] = getAllTurnPts();
        if (pts == null) {
            if (mNavStart.pos.lon == 0) {
                MinLon = previewLon;
                MinLat = previewLat;
                MaxLon = MinLon;
                MaxLat = MinLat;
            } else {
                MinLon = mNavStart.pos.lon;
                MinLat = mNavStart.pos.lat;
                MaxLon = mNavStart.pos.lon;
                MaxLat = mNavStart.pos.lat;
            }

            if (mNavDest == null) {
                return;
            }

            long wPtNum = mNavDest.length;
            for (int i = 0; i < wPtNum; i++) {
                if (mNavDest[i].pos.lon < MinLon) {
                    MinLon = mNavDest[i].pos.lon;
                }

                if (mNavDest[i].pos.lat < MinLat) {
                    MinLat = mNavDest[i].pos.lat;
                }

                if (mNavDest[i].pos.lon > MaxLon) {
                    MaxLon = mNavDest[i].pos.lon;
                }

                if (mNavDest[i].pos.lat > MaxLat) {
                    MaxLat = mNavDest[i].pos.lat;
                }
            }
        } else {
            long wPtNum = pts.length;
            for (int i = 0; i < wPtNum; i++) {
                if (pts[i].lon < MinLon) {
                    MinLon = pts[i].lon;
                }

                if (pts[i].lat < MinLat) {
                    MinLat = pts[i].lat;
                }

                if (pts[i].lon > MaxLon) {
                    MaxLon = pts[i].lon;
                }

                if (pts[i].lat > MaxLat) {
                    MaxLat = pts[i].lat;
                }
            }
        }

        LonLat pos = new LonLat((MinLon + MaxLon) / 2, (MinLat + MaxLat) / 2);
        setMapCenter(pos);
        LonLat posA = new LonLat(MinLon, MinLat);
        LonLat posB = new LonLat(MaxLon, MaxLat);
        double distance = getDistance(posA, posB);

        if (distance < 500) {
            setScale(100000);
        } else if (distance < 1000) {
            setScale(50000);
        } else if (distance < 2000) {
            setScale(25000);
        } else if (distance < 4000) {
            setScale(10000);
        } else if (distance < 8000) {
            setScale(5000);
        } else if (distance < 16000) {
            setScale(2500);
        } else if (distance < 32000) {
            setScale(1000);
        } else if (distance < 64000) {
            setScale(500);
        } else if (distance < 128000) {
            setScale(250);
        } else if (distance < 256000) {
            setScale(125);
        } else {
            setScale(50);
        }
    }

    public int blockAtDistance(double distance) {
        return NavFrameSDK.getInstance().BlockAtDistance(mGIS, distance);
    }

    public int reroute(boolean isChooseHW) {
        return NavFrameSDK.getInstance().Reroute(mGIS, isChooseHW);
    }

    public void clearRoute() {
        if (mGIS != 0) {
            NavFrameSDK.getInstance().ClearRoute(mGIS);
        }
    }

    public void clearMultiRoute() {
        if (mGIS == 0)
            return;
        NavFrameSDK.getInstance().ClearMultiRoute(mGIS);
    }

    public int getRoutingProcess() {
        if (mGIS == 0)
            return -1;
        return NavFrameSDK.getInstance().GetRoutingProcess(mGIS);
    }

    public CLonLat[] getRouteAllPts() {
        return NavFrameSDK.getInstance().GetRouteAllPts(mGIS);
    }

    public void initPathSimu() {
        NavFrameSDK.getInstance().InitPathSimu(mGIS);
    }

    public boolean getNextSimuData(NavPosition navpos, int simuStep) {
        return NavFrameSDK.getInstance()
                .GetNextSimuData(mGIS, navpos, simuStep);
    }

    public CLonLat[] getAllTurnPts() {
        return NavFrameSDK.getInstance().GetAllTurnPts(mGIS);
    }

    public CLonLat[] getPathPts() {
        return NavFrameSDK.getInstance().GetPathTurnPts(mGIS, true);
    }

    public boolean addBlockEdge(CLonLat ll, int eid) {
        return NavFrameSDK.getInstance().AddBlockEdge(mGIS, ll, eid);
    }

    public boolean removeBlockEdge(CLonLat ll, int eid) {
        return NavFrameSDK.getInstance().RemoveBlockEdge(mGIS, ll, eid);
    }

    public void clearBlockEdge() {
        NavFrameSDK.getInstance().ClearBlockEdge(mGIS);
    }

    public void setCoutryId(String countryId) {
        NavFrameSDK.getInstance().SetCoutryId(mGIS, countryId);
    }

    public SignPostInfo mSignpostInfo = null;

    // Nav
    // roadtype: FLAT = 0, RAMP, SERVICEROAD, FREEWAY, ROUNDABOUT, TUNNEL,
    // FERRY, SERVICE, INNERLINK
    public synchronized SDCurPosStates UpdatePosition(NavPosition pPos,
                                                      NavPosition pMatchedPos, NavInfo pNavInfo) {

        return NavFrameSDK.getInstance().UpdatePosition(mGIS, pPos,
                pMatchedPos, pNavInfo);
    }

    @SuppressWarnings("unused")
    private int getAdaId(CLonLat pos) {
        AreaDescription areaDescription = NavFrameSDK.getInstance().new AreaDescription();
        areaDescription.axid = 0;
        boolean ret = getAreaByPoint(pos, areaDescription);
        if (!ret) {
            areaDescription.axid = 0;
        }

        int adaID = areaDescription.axid;
        String str = Integer.toString(adaID) + "00";
        adaID = Integer.parseInt(str, 16);

        return adaID;
    }

    public boolean prepareTurnAndGuid() {
        return NavFrameSDK.getInstance().PrepareTurnAndGuid(mGIS);
    }

    public int prepareCurTurnAndGuid() {
        return NavFrameSDK.getInstance().PrepareCurTurnAndGuid(mGIS);
    }

    public boolean nextTurnAndGuid(TurnInfo pTurnInfo, GuideInfo pGuidInfo,
                                   CLonLat pPos) {
        return NavFrameSDK.getInstance().NextTurnAndGuid(mGIS, pTurnInfo,
                pGuidInfo, pPos);
    }

    public void finishTurnAndGuid() {
        NavFrameSDK.getInstance().FinishTurnAndGuid(mGIS);
    }

    // query
    public synchronized long getRootAda() {
        return NavFrameSDK.getInstance().GetRootAda(mGIS);
    }

    public synchronized int prepareChildAda(int hGIS, long parentAdaID) {
        return NavFrameSDK.getInstance().PrepareChildAda(mGIS, parentAdaID);
    }

    public synchronized boolean getNextChildAda(int hAda, long childAda,
                                                AreaDescription ada, CLonLat center) {
        boolean ret = NavFrameSDK.getInstance().GetNextChildAda(mGIS, hAda,
                childAda, ada, center);
        return ret;
    }

    public synchronized void finishGetNextChildAda(int hAda) {
        NavFrameSDK.getInstance().FinishGetNextChildAda(mGIS, hAda);
    }

    public synchronized boolean GetLLAda(CLonLat ll, long adaID,
                                         AreaDescription ada) {
        return NavFrameSDK.getInstance().GetLLAda(mGIS, ll, adaID, ada);
    }

    public synchronized boolean IsLLInAda(CLonLat ll, long adaID) {
        return NavFrameSDK.getInstance().IsLLInAda(mGIS, ll, adaID);
    }

    public synchronized boolean preparePOIByPoint(CLonLat pt, String poiType,
                                                  String name, double searchRange) {

        try {
            return NavFrameSDK.getInstance().PreparePOIByPoint(mGIS, pt,
                    poiType, name, searchRange);
        } catch (Exception e) {
            return false;
        }
    }

    public synchronized boolean preparePOIByRect(CLonLat bottomLeft,
                                                 CLonLat topRight, String poiType) {
        return NavFrameSDK.getInstance().PreparePOIByRect(mGIS, bottomLeft,
                topRight, poiType);
    }

    public synchronized boolean preparePOIByName(String name, long adaID,
                                                 String poiType) {
        return NavFrameSDK.getInstance().PreparePOIByName(mGIS, name, adaID,
                poiType);
    }

    public synchronized boolean getNextPOI(POIDescription poiDesription) {
        return NavFrameSDK.getInstance().GetNextPOI(mGIS, poiDesription);
    }

    public synchronized void finishGetPOI() {
        NavFrameSDK.getInstance().FinishGetPOI(mGIS);
    }

    public synchronized boolean prepareRoadByPoint(CLonLat pt,
                                                   double searchRange) {
        return NavFrameSDK.getInstance().PrepareRoadByPoint(mGIS, pt,
                searchRange);
    }

    public synchronized boolean prepareRoadByName(String name, long adaID) {
        return NavFrameSDK.getInstance().PrepareRoadByName(mGIS, name, adaID);
    }

    public synchronized boolean getNextRoad(RoadDescription roadDesription) {
        return NavFrameSDK.getInstance().GetNextRoad(mGIS, roadDesription);
    }

    public synchronized void finishGetRoad() {
        NavFrameSDK.getInstance().FinishGetRoad(mGIS);
    }

    public synchronized boolean getAreaByPoint(CLonLat pt, AreaDescription ada) {
        boolean ret = NavFrameSDK.getInstance().GetAreaByPoint(mGIS, pt, ada);

        String[] name = ada.name.split(";");
        String a002 = "";
        String a003 = "";
        for (int i = 0; i < name.length && i < 2; i++) {
            if (i == 0) {
                a002 = name[i];
            } else {
                a003 = name[i];
            }
        }
        if (a003.length() > 1) {
            ada.name = a003;
        } else {
            ada.name = a002;
        }

        return ret;
    }

    // Smart Query
    public synchronized boolean startQueryCity(String keyword, int ownerAdaID,
                                               int type) {
        return NavFrameSDK.getInstance().SQStartQueryCity(mhSQ, keyword,
                ownerAdaID, type);
    }

    public synchronized boolean getResultCity(int nIndex, AreaDescription area) {
        return NavFrameSDK.getInstance().SQGetResultCity(mhSQ, nIndex, area);
    }

    public String getKeypadCity() {
        return "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    }

    public boolean startQueryPOIHanzi(String keyword, int owner, int type) {
        return NavFrameSDK.getInstance().SQStartQueryPOIHanzi(mhSQ, keyword,
                owner, type);
    }

    public synchronized boolean startQueryPOI(String keyword, int owner,
                                              int type) {
        return NavFrameSDK.getInstance().SQStartQueryPOI(mhSQ, keyword, owner,
                type);
    }

    public synchronized boolean getResultPOI(POIDescription poiDesription,
                                             int nIndex) {
        return NavFrameSDK.getInstance().SQGetResultPOI(mhSQ, poiDesription,
                nIndex);
    }

    public List<POIDescription> mPOIResult = new ArrayList<POIDescription>();

    // get tip info (POI + Road)
    public String getposInfo(LonLat mapPt) {
        CLonLat pos = NavFrameSDK.getInstance().new CLonLat();
        pos.lon = mapPt.GetLon();
        pos.lat = mapPt.GetLat();

        String txtInfo = "";
        POIDescription poiDesription = NavFrameSDK.getInstance().new POIDescription();
        if (preparePOIByPoint(pos, "All POI", "", 10)
                && getNextPOI(poiDesription)) {
            txtInfo = poiDesription.name;
        }
        finishGetPOI();

        if (txtInfo.length() > 1)
            return txtInfo;

        RoadDescription roadDesription = NavFrameSDK.getInstance().new RoadDescription();
        if (prepareRoadByPoint(pos, 50)) {
            while (getNextRoad(roadDesription)) {
                if (roadDesription.name != null) {
                    txtInfo = roadDesription.name;
                    break;
                }
            }
        }
        finishGetRoad();

        if (txtInfo.length() > 1)
            return txtInfo;

        txtInfo = "您的位置-" + (float) pos.lon + " " + (float) pos.lat;

        return txtInfo;
    }

    public String getRoadnamebypos(LonLat mapPt) {
        String txtInfo = "";

        CLonLat pos = NavFrameSDK.getInstance().new CLonLat();
        pos.lon = mapPt.GetLon();
        pos.lat = mapPt.GetLat();

        RoadDescription roadDesription = NavFrameSDK.getInstance().new RoadDescription();
        if (prepareRoadByPoint(pos, 10)) {
            while (getNextRoad(roadDesription)) {
                if (roadDesription.name != null) {
                    txtInfo = roadDesription.name.replace("*", " ");
                    break;
                }
            }
        }
        finishGetRoad();

        return txtInfo;
    }

    // 得到axid对应的adaId
    public synchronized long getAdaId(int axid) {
        long adaID = 0;
        POIDescription poiDesription = NavFrameSDK.getInstance().new POIDescription();
        try {
            if (startQueryPOIHanzi("", axid, 35)) {
                getResultPOI(poiDesription, 0);
            }
        } catch (Exception e) {

        }

        adaID = NavFrameSDK.getInstance().GetCityAdaID(mGIS,
                poiDesription.position.lon, poiDesription.position.lat);

        return adaID;
    }

    public synchronized long getAdaId(double lon, double lat) {

        return NavFrameSDK.getInstance().GetCityAdaID(mGIS, lon, lat);
    }

    public synchronized String getposCityInfo() {
        CLonLat pos = NavFrameSDK.getInstance().new CLonLat();
        NavFrameSDK.getInstance().GetMapCenter(mGIS, pos);

        String txtInfo = "";
        AreaDescription areaDescription = NavFrameSDK.getInstance().new AreaDescription();
        if (getAreaByPoint(pos, areaDescription)) {
            txtInfo = areaDescription.name;
            txtInfo = txtInfo.replace(";", "");
        }
        return txtInfo;
    }

    public synchronized String getposCityInfo(double lon, double lat) {
        CLonLat pos = NavFrameSDK.getInstance().new CLonLat();
        pos.lon = lon;
        pos.lat = lat;

        String txtInfo = "";
        AreaDescription areaDescription = NavFrameSDK.getInstance().new AreaDescription();
        if (getAreaByPoint(pos, areaDescription)) {
            txtInfo = areaDescription.name;
            txtInfo = txtInfo.replace(";", " ");
        }
        return txtInfo;
    }

    public ArrayList<POIDescription> mParkList = new ArrayList<POIDescription>();
    public LonLat mParkCenter = new LonLat();

    public void removePark() {
        mParkCenter.SetInvalid();
        mParkList.clear();
    }

    public boolean setNearPark(LonLat pos) {
        if (mGIS == 0)
            return false;

        if (!pos.IsValid()) {
            removePark();
            return false;
        }

        if (mParkCenter != pos) {
            mParkCenter = pos;
            mParkList.clear();
            ArrayList<POIDescription> parkList = new ArrayList<POIDescription>();
            CLonLat centerPos = NavFrameSDK.getInstance().new CLonLat();
            centerPos.lon = mParkCenter.GetLon();
            centerPos.lat = mParkCenter.GetLat();
            if (preparePOIByPoint(centerPos, "52.停车场", "", 500)) {
                while (true) {
                    POIDescription poiDesription = NavFrameSDK.getInstance().new POIDescription();
                    if (!getNextPOI(poiDesription))
                        break;
                    LonLat ll = new LonLat(poiDesription.position.lon,
                            poiDesription.position.lat);
                    poiDesription.rank = (int) getDistance(mParkCenter, ll);
                    parkList.add(poiDesription);
                }
            }

            if (parkList.size() > 0) {
                Collections.sort(parkList, poiResultFunc);
            }

            for (int i = 0; i < parkList.size(); i++) {
                POIDescription poiDesription = parkList.get(i);
                mParkList.add(poiDesription);
                i++;
                if (i >= 5)
                    break;
            }
            finishGetPOI();
        }

        return true;
    }

    private final static Comparator<POIDescription> poiResultFunc = new Comparator<POIDescription>() {
        @Override
        public int compare(POIDescription object1, POIDescription object2) {
            return object1.rank - object2.rank;
        }
    };

    public ArrayList<POIDescription> mTipPoiList = null;

    public ArrayList<POIDescription> getNearPoi(LonLat mapPt, boolean isTip) {
        ArrayList<POIDescription> poiList = new ArrayList<POIDescription>();
        if (mapPt == null) {
            return poiList;
        }

        CLonLat llnew = NavFrameSDK.getInstance().new CLonLat();
        llnew.lon = mapPt.GetLon();
        llnew.lat = mapPt.GetLat();

        CLonLat pos = NavFrameSDK.getInstance().new CLonLat();
        pos.lon = mapPt.GetLon();
        pos.lat = mapPt.GetLat();

        int m = getScaleInMeter()/2;//比例尺的显示
        int range = 50;
        if (m < range) {
            range = m;
        }

        if (!isTip) {
            range = 60;
        }

        String strCat = "";
        String strPcode = "";
        if (preparePOIByPoint(pos, "All POI", "", range)) {
            while (true) {
                POIDescription poiDesription = NavFrameSDK.getInstance().new POIDescription();
                if (!getNextPOI(poiDesription))
                    break;
                LonLat ll = new LonLat();
                ll.SetLonLat(poiDesription.position.lon,
                        poiDesription.position.lat);

                strCat = "";
                strPcode = "";
                String strz = "";
                try {
                    strCat = new String(poiDesription.pcode, 6, 1, "gbk");
                    strPcode = new String(poiDesription.pcode, 0, 4, "gbk");
                    strz = new String(poiDesription.pcode, "gbk");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }

                // P213;110;1
                if (poiDesription.pcode[9] > 0)
                    continue;

                // P920
                if (strPcode.contains("P9"))
                    continue;

                int distance = (int) getDistance(mapPt, ll);
                if (distance > 10) {
                    poiDesription.rank = distance * 10000;
                } else {
                    poiDesription.rank = Integer.parseInt(strCat) * 100
                            + distance;
                }
                poiList.add(poiDesription);
            }

            if (poiList.size() > 0) {
                Collections.sort(poiList, poiResultFunc);
            }
        }
        finishGetPOI();

        int rangeR[] = {5, 10, 20, 30, 50, 100, 200, 500, 600};
        int index = -1;
        if (isTip) {
            index = 0;
            range = rangeR[0];
        }

        if (poiList.size() < 1) {
            while (true) {
                RoadDescription roadDesription = NavFrameSDK.getInstance().new RoadDescription();
                if (prepareRoadByPoint(pos, range)) {
                    while (getNextRoad(roadDesription)) {
                        POIDescription poiDesription = NavFrameSDK
                                .getInstance().new POIDescription();
                        poiDesription.name = roadDesription.name.replace("*",
                                " ");
                        if (poiDesription.name.length() < 3) {
//                            poiDesription.name = "无名道路";
                            poiDesription.name = "";
                        }
                        if (range > 50) {
                            poiDesription.name += "(附近)";
                        }
                        poiDesription.position = pos;
                        poiList.add(poiDesription);
                    }
                }
                finishGetRoad();

                if (isTip) {
                    break;
                }

                if (poiList.size() > 0) {
                    Collections.sort(poiList, poiResultFunc);
                    POIDescription poiDesription = poiList.get(0);
                    poiList.clear();
                    poiList.add(poiDesription);
                    break;
                }

                if (range > 500)
                    break;

                if (index >= 0 && index < rangeR.length) {
                    index++;
                    range = rangeR[index];
                } else {
                    break;
                }
            }
        }

        if (poiList.size() < 1) {
            POIDescription poiDesription = NavFrameSDK
                    .getInstance().new POIDescription();
            poiDesription.name = "   ";
            poiDesription.position = pos;
            poiList.add(poiDesription);
        }

        return poiList;
    }

    public synchronized String getNearRoadName(LonLat mapPt) {
        CLonLat pos = NavFrameSDK.getInstance().new CLonLat();
        pos.lon = mapPt.GetLon();
        pos.lat = mapPt.GetLat();

        String roadName = "";
        RoadDescription roadDesription = NavFrameSDK.getInstance().new RoadDescription();
        if (prepareRoadByPoint(pos, 20)) {
            while (getNextRoad(roadDesription)) {
                if (roadDesription.name.length() > 2) {
                    roadName = roadDesription.name.replace("*", " ");
                    break;
                }
            }
        }
        finishGetRoad();
        return roadName;
    }

    public SearchParm mSearchParm = new SearchParm();
    public ArrayList<String> mSStypeList = new ArrayList<String>();

    @SuppressLint("DefaultLocale")
    public boolean smartQuery(boolean needSetResult) {
        if (mGIS == 0)
            return false;

        String keyword = mSearchParm.keyword;
        int owner = mSearchParm.owner;
        int type = mSearchParm.type;
        boolean isABC = mSearchParm.isABC;
        CLonLat center = NavFrameSDK.getInstance().new CLonLat();
        center.lon = mSearchParm.dLon;
        center.lat = mSearchParm.dLat;

        keyword = keyword.toUpperCase();

        mPOIResult.clear();
        ArrayList<POIDescription> poiResult = new ArrayList<POIDescription>();

        boolean haveN = false;
        String a = "";
        String b = "";
        String c = "";
        if (keyword.length() > 1) {
            for (int i = 0; i < mSStypeList.size(); i++) {
                String[] typeName = mSStypeList.get(i).split("@");
                a = "";
                b = "";
                c = "";
                for (int j = 0; j < typeName.length; j++) {
                    if (j == 0) {
                        a = typeName[j];
                    } else if (j == 1) {
                        b = typeName[j];
                    } else if (j == 2) {
                        c = typeName[j];
                    }
                }
                if (a.length() > 1 && keyword.contains(a)) {
                    haveN = true;
                    break;
                }
            }
        }

        if (c.length() > 0) {
            keyword = keyword.replace(a, c);
        }

        int num = 0;
        if (!isABC) {
            if (!startQueryPOIHanzi(keyword, owner, type))
                return false;
        } else {
            if (!startQueryPOI(keyword, owner, type))
                return false;
        }

        if (!needSetResult)
            return true;

        boolean isGood = false;
        String name = "";
        String pcode = "";
        String cname = "";
        int maxnum = 50;
        if (keyword.length() > 3) {
            maxnum = 1000;
        } else if (keyword.length() > 0) {
            maxnum = 100;
        }

        LonLat centerPos = new LonLat();
        centerPos.SetLonLat(center.lon, center.lat);

        while (num < maxnum) {
            POIDescription poiDesription = NavFrameSDK.getInstance().new POIDescription();
            if (!getResultPOI(poiDesription, num))
                break;
            LonLat pos = new LonLat();
            pos.SetLonLat(poiDesription.position.lon,
                    poiDesription.position.lat);
            poiDesription.rank = (int) getDistance(centerPos, pos) + 1300000000;
            isGood = false;
            name = poiDesription.name;
            name = name.toUpperCase();
            try {
                pcode = new String(poiDesription.pcode, "utf-8");
                pcode = pcode.substring(0, 4);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            if (haveN) {
                if (pcode.length() > 0 && b.compareToIgnoreCase(pcode) == 0) {
                    isGood = true;
                }
            }

            if (isGood) {
                poiDesription.rank -= 1000000000;
            }

            if (name.compareToIgnoreCase(keyword) == 0) {
                poiDesription.rank -= 300000000;
            } else if (name.startsWith(keyword)) {
                poiDesription.rank -= 200000000;
            } else if (name.contains(keyword)) {
                poiDesription.rank -= 100000000;
            }

            poiResult.add(poiDesription);
            num++;
            if (num >= maxnum)
                break;
        }

        if (poiResult.size() > 0) {
            Collections.sort(poiResult, poiResultFunc);
        }

        for (int i = 0; i < poiResult.size(); i++) {
            POIDescription poiDesription = poiResult.get(i);
            mPOIResult.add(poiDesription);
            if (i >= 100)
                break;
        }

        return (num > 0);
    }

    public boolean getResultAfterSmartQuery() {
        if (mGIS == 0)
            return false;

        LonLat center = new LonLat(mSearchParm.dLon, mSearchParm.dLat);
        int num = 0;
        while (num < 100) {
            POIDescription poiDesription = NavFrameSDK.getInstance().new POIDescription();
            if (!getResultPOI(poiDesription, num))
                break;
            LonLat pos = new LonLat(poiDesription.position.lon,
                    poiDesription.position.lat);
            poiDesription.rank = (int) getDistance(center, pos);
            mPOIResult.add(poiDesription);
            num++;
            if (num >= 100)
                break;
        }

        if (mPOIResult.size() > 0) {
            Collections.sort(mPOIResult, poiResultFunc);
        }

        return (num > 0);
    }

    public int nearQuery0(boolean bOrderByName) {
        mPOIResult.clear();

        if (mGIS == 0)
            return -1;

        String poiType = mSearchParm.poiType;
        String nameKey = mSearchParm.keyword.trim();
        CLonLat center = NavFrameSDK.getInstance().new CLonLat();
        center.lon = mSearchParm.dLon;
        center.lat = mSearchParm.dLat;

        if (preparePOIByPoint(center, poiType, nameKey, 500000)) {
            while (true) {
                POIDescription poiDesription = NavFrameSDK.getInstance().new POIDescription();
                if (!getNextPOI(poiDesription))
                    break;
                mPOIResult.add(poiDesription);
            }
        }

        finishGetPOI();
        return mPOIResult.size();
    }

    private static final double TOLERANCE = 0.000003;

    public boolean isEqualCLonLat(CLonLat pt1, CLonLat pt2) {
        double dLon = pt1.lon - pt2.lon;
        double dLat = pt1.lat - pt2.lat;
        if (dLon < 0)
            dLon = -dLon;
        if (dLat < 0)
            dLat = -dLat;
        return (dLon < TOLERANCE && dLat < TOLERANCE);
    }

    public boolean isEqualNavpos(NavPosition navpos1, NavPosition navpos2) {
        if (!isEqualCLonLat(navpos1.pos, navpos2.pos))
            return false;

        double dir = navpos1.dir - navpos2.dir;
        if (dir < 0)
            dir = -dir;
        return (dir < TOLERANCE && dir < TOLERANCE);
    }

    public String getDirection(LonLat start, LonLat ll) {
        Point pt = new Point();
        Point ptNext = new Point();
        pt.x = (int) (start.GetLat() * 1000000);
        pt.y = (int) (start.GetLon() * 1000000);

        ptNext.x = (int) (ll.GetLat() * 1000000);
        ptNext.y = (int) (ll.GetLon() * 1000000);

        double angle = getAngleOfTwoPoint(pt, ptNext);

        String[] dir_names = AppContext.getInstances().getResources().getStringArray(R.array.dir_names);
        String strDir = new String();
        if (0 <= angle && angle < 22.5 || 337.5 <= angle && angle < 360) {
            strDir = dir_names[0];
        } else if (22.5 <= angle && angle < 67.5) {
            strDir = dir_names[1];
        } else if (67.5 <= angle && angle < 112.5) {
            strDir = dir_names[2];
        } else if (112.5 <= angle && angle < 157.5) {
            strDir = dir_names[3];
        } else if (157.5 <= angle && angle < 202.5) {
            strDir = dir_names[4];
        } else if (202.5 <= angle && angle < 247.5) {
            strDir = dir_names[5];
        } else if (247.5 <= angle && angle < 292.5) {
            strDir = dir_names[6];
        } else if (292.5 <= angle && angle < 337.5) {
            strDir = dir_names[7];
        }
        return strDir;
    }

    public double getDirection3(LonLat start, LonLat ll) {
        Point pt = new Point();
        Point ptNext = new Point();
        pt.x = (int) (start.GetLat() * 1000000);
        pt.y = (int) (start.GetLon() * 1000000);

        ptNext.x = (int) (ll.GetLat() * 1000000);
        ptNext.y = (int) (ll.GetLon() * 1000000);

        double angle = getAngleOfTwoPoint(pt, ptNext);
        return angle;
    }

    public double getDirection2(NavFrameSDK.CLonLat start,
                                NavFrameSDK.CLonLat ll) {
        Point pt = new Point();
        Point ptNext = new Point();
        pt.x = (int) (start.lat * 1000000);
        pt.y = (int) (start.lon * 1000000);

        ptNext.x = (int) (ll.lat * 1000000);
        ptNext.y = (int) (ll.lon * 1000000);

        double angle = getAngleOfTwoPoint(pt, ptNext);
        return angle;
    }

    final static double PI = 3.1415926535897932384626433832795;
    final static double RAD2DEG = 57.295779513082320876798154814105;

    public double getAngleOfTwoPoint(Point pt1, Point pt2) {
        double angle = 0.0;
        int nX = pt2.x - pt1.x;
        int nY = pt1.y - pt2.y;

        double dAtan2 = Math.atan2(nY, nX);
        if (dAtan2 > 0) {
            angle = dAtan2 * RAD2DEG;
        } else {
            angle = (2 * PI + dAtan2) * RAD2DEG;
        }
        angle = 360 - angle;
        return angle;
    }

    String mSunriseTime = "";
    String mSunsetTime = "";

    // return format must be HH:mm
    @SuppressLint({"DefaultLocale", "SimpleDateFormat"})
    public String getSunriseTime() {
        double lon = SystemSetFileHandle.getInstance().getSystemSet().previewLon;
        double lat = SystemSetFileHandle.getInstance().getSystemSet().previewLat;
        Date date = new Date();
        SimpleDateFormat dateformat = new SimpleDateFormat("D");
        String d = dateformat.format(date);
        int day = Integer.parseInt(d);
        double t = getSunrise(lon, lat, day);
        int hour = (int) t;
        double dm = (t - hour) * 60;
        int min = (int) dm;
        String ret = String.format("%02d:%02d", hour, min);
        return ret;
    }

    // return format must be HH:mm
    @SuppressLint({"SimpleDateFormat", "DefaultLocale"})
    public String getSunsetTime() {
        double lon = SystemSetFileHandle.getInstance().getSystemSet().previewLon;
        double lat = SystemSetFileHandle.getInstance().getSystemSet().previewLat;
        Date date = new Date();
        SimpleDateFormat dateformat = new SimpleDateFormat("D");
        String d = dateformat.format(date);
        int day = Integer.parseInt(d);
        double t = getSunset(lon, lat, day);
        int hour = (int) t;
        double dm = (t - hour) * 60;
        int min = (int) dm;
        String ret = String.format("%02d:%02d", hour, min);
        return ret;
    }

    private int TIMEZONE = 8; // china time zone

    private double getSunrise(double lon, double lat, int day) {
        double pi = Math.PI;
        double degday = Math.cos(2 * pi * (day + 9) / 365);
        double diff = Math.acos(-Math.tan(-23.4 * degday * pi / 180)
                * Math.tan(lat * pi / 180))
                * 180 / pi;
        double t = 24 * (180 + TIMEZONE * 15 - lon - diff) / 360;
        return t;
    }

    private double getSunset(double lon, double lat, int day) {
        double sunrise = getSunrise(lon, lat, day);
        double t = 24 * (1 + (TIMEZONE * 15 - lon) / 180) - sunrise;
        return t;
    }

    // 求当前位置地图距离dis对应屏幕像素值
    public int meterDis2Pix(int nDis, int mapWidth) {
        if (mGIS == 0)
            return 0;

        int nresult = 0;

        CLonLat cll = NavFrameSDK.getInstance().new CLonLat();
        NavFrameSDK.getInstance().GetMapCenter(mGIS, cll);

        double dScale = getScale();
        double dlatPreMeter = 0;
        double dlonPreMeter = 0;
        CllDegreePreMeter llDegree = NavFrameSDK.getInstance().new CllDegreePreMeter();
        NavFrameSDK.getInstance().GetUnitDegree(mGIS, cll.lon, cll.lat,
                llDegree);
        nresult = (int) (dScale * llDegree.latdegree * nDis);

        LonLat mapPt1 = XY2LL(new Point(0, 0));
        LonLat mapPt2 = XY2LL(new Point(mapWidth, 0));
        nresult = (int) (nDis / getDistance(mapPt1, mapPt2) * mapWidth);

        return nresult;
    }

    //range -- 米 => 经纬度/米(每米表示的经纬度)
    public CllDegreePreMeter GetUnitDegree() {
        if (mGIS == 0)
            return null;
        CLonLat cll = NavFrameSDK.getInstance().new CLonLat();
        NavFrameSDK.getInstance().GetMapCenter(mGIS, cll);

        CllDegreePreMeter llDegree = NavFrameSDK.getInstance().new CllDegreePreMeter();
        NavFrameSDK.getInstance().GetUnitDegree(mGIS, cll.lon, cll.lat,
                llDegree);

        return llDegree;
    }

    public NavFrameSDK.CLenPreLonlat GetUnitLength() {
        if (mGIS == 0)
            return null;
        CLonLat cll = NavFrameSDK.getInstance().new CLonLat();
        NavFrameSDK.getInstance().GetMapCenter(mGIS, cll);
        NavFrameSDK.CLenPreLonlat lenpre = NavFrameSDK.getInstance().new CLenPreLonlat();
        NavFrameSDK.getInstance().GetUnitLength(mGIS, cll.lon, cll.lat,
                lenpre);
        return lenpre;
    }


    public void showFullPath() {
        double MinLon = 10000;
        double MinLat = 10000;
        double MaxLon = -1000;
        double MaxLat = -1000;
        CLonLat pts[] = getAllTurnPts();
        if (pts == null) {
            if (mNavStart.pos.lon == 0) {
                MinLon = SystemSetFileHandle.getInstance().getSystemSet().previewLon;
                MinLat = SystemSetFileHandle.getInstance().getSystemSet().previewLat;
                MaxLon = MinLon;
                MaxLat = MinLat;
            } else {
                MinLon = mNavStart.pos.lon;
                MinLat = mNavStart.pos.lat;
                MaxLon = mNavStart.pos.lon;
                MaxLat = mNavStart.pos.lat;
            }

            if (mNavDest == null) {
                return;
            }

            long wPtNum = mNavDest.length;
            for (int i = 0; i < wPtNum; i++) {
                if (mNavDest[i].pos.lon < MinLon) {
                    MinLon = mNavDest[i].pos.lon;
                }

                if (mNavDest[i].pos.lat < MinLat) {
                    MinLat = mNavDest[i].pos.lat;
                }

                if (mNavDest[i].pos.lon > MaxLon) {
                    MaxLon = mNavDest[i].pos.lon;
                }

                if (mNavDest[i].pos.lat > MaxLat) {
                    MaxLat = mNavDest[i].pos.lat;
                }
            }
        } else {
            long wPtNum = pts.length;
            for (int i = 0; i < wPtNum; i++) {
                if (pts[i].lon < MinLon) {
                    MinLon = pts[i].lon;
                }

                if (pts[i].lat < MinLat) {
                    MinLat = pts[i].lat;
                }

                if (pts[i].lon > MaxLon) {
                    MaxLon = pts[i].lon;
                }

                if (pts[i].lat > MaxLat) {
                    MaxLat = pts[i].lat;
                }
            }
        }

        // double xLon = MaxLon - MinLon;
        // double xLat = MaxLat - MinLat;
        // MinLon = MinLon - xLon;
        // MinLat = MinLat - xLat;
        // MaxLon = MaxLon + xLon;
        // MaxLat = MaxLat + xLat;
        // rescaleAndTranslateToFit(MinLon, MinLat, MaxLon, MaxLat);

        LonLat pos = new LonLat((MinLon + MaxLon) / 2, (MinLat + MaxLat) / 2);
        setMapCenter(pos);
        LonLat posA = new LonLat(MinLon, MinLat);
        LonLat posB = new LonLat(MaxLon, MaxLat);
        double distance = getDistance(posA, posB);

        if (distance < 500) {
            setScale(100000);
        } else if (distance < 1000) {
            setScale(50000);
        } else if (distance < 2000) {
            setScale(25000);
        } else if (distance < 4000) {
            setScale(10000);
        } else if (distance < 8000) {
            setScale(5000);
        } else if (distance < 16000) {
            setScale(2500);
        } else if (distance < 32000) {
            setScale(1000);
        } else if (distance < 64000) {
            setScale(500);
        } else if (distance < 128000) {
            setScale(250);
        } else if (distance < 256000) {
            setScale(125);
        } else {
            setScale(50);
        }
    }

    public int nearQuery(boolean bOrderByName) {
        mPOIResult.clear();

        if (mGIS == 0)
            return -1;

        String poiType = mSearchParm.poiType;
        String nameKey = mSearchParm.keyword.trim();
        LonLat centerPos = new LonLat(mSearchParm.dLon, mSearchParm.dLat);
        CLonLat center = NavFrameSDK.getInstance().new CLonLat();
        center.lon = centerPos.GetLon();
        center.lat = centerPos.GetLat();
        LonLat carPos = new LonLat(mSearchParm.dLonCar, mSearchParm.dLatCar);

        List<POIDescription> poiResult = new ArrayList<POIDescription>();
        int num = 0;
        int range = mSearchParm.range;
        if (range == 3000) {
            // 查询范围为3000，则为周边查询
            if (nameKey.length() < 1) {
                if (poiType.compareToIgnoreCase("All POI") == 0) {
                    range = 500;
                } else {
                    range = 2000;
                }
            }
        } else {
            if (nameKey.length() > 2) {
                range = 50000;
            }
        }

        if (poiType.compareToIgnoreCase("City") == 0) {
            range = mSearchParm.range;
        }

        String pcode = "";

        while (num < 1) {
            num = 0;
            poiResult.clear();
            if (preparePOIByPoint(center, poiType, nameKey, range)) {
                while (num < 2000) {
                    POIDescription poiDesription = NavFrameSDK.getInstance().new POIDescription();
                    if (!getNextPOI(poiDesription))
                        break;
                    poiResult.add(poiDesription);
                    num++;
                    if (num >= 2000)
                        break;
                }
            }

            range += 5000;
            finishGetPOI();

            if (range >= 50000)
                break;
        }

        List<POIDescription> poiResult2 = new ArrayList<POIDescription>();
        for (POIDescription poiDesription : poiResult) {
            if (poiDesription.name.length() < 1)
                continue;

            if (nameKey.length() > 0 && nameKey.charAt(0) > 'z') {
                if (!poiDesription.name.contains(nameKey)) {
                    continue;
                }
            }

            // P213;110;1
            if (nameKey.length() < 1 && poiDesription.pcode[9] > 0)
                continue;
            LonLat pos = new LonLat(poiDesription.position.lon,
                    poiDesription.position.lat);

            int distance = (int) getDistance(carPos, pos);
            poiDesription.rank = distance;
            poiResult2.add(poiDesription);
        }

        if (poiResult2.size() > 0) {
            Collections.sort(poiResult2, poiResultFunc);
        }

        num = 0;
        for (int i = 0; i < poiResult2.size(); i++) {
            POIDescription poi = poiResult2.get(i);
            boolean havesame = false;
//            String strPcode = "";
//            try {
//                strPcode = new String(poi.pcode, 0, 4, "gbk");
//            } catch (UnsupportedEncodingException e) {
//                e.printStackTrace();
//            }

//            for (int j = 0; j < mPOIResult.size(); j++) {
//                POIDescription poiT = mPOIResult.get(j);
//                int distance = (int) NavFrameSDK.getInstance().GetDistance(
//                        mGIS, poi.position, poiT.position);
//                if (distance < 100 && poi.name.contains(poiT.name)) {
//                    havesame = true;
//                    if (strPcode.contains("P96")) {
//                        mPOIResult.set(j, poi);
//                    }
//                    break;
//                }
//            }
            if (!havesame) {
                num++;
                mPOIResult.add(poi);
            }

            if (num >= 100)
                break;
        }
        return num;
    }

    public void queryCitys(String strKeyword) {
        SearchParm sp = new SearchParm();
        sp.dLon = 121.476455;
        sp.dLat = 31.231706;
        sp.poiType = "City";
        sp.range = 10000000;
        sp.keyword = strKeyword;
        mSearchParm = sp;
        nearQuery(false);
    }
}
